/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.modules.web.core;
import java.util.Set;
import java.util.Iterator;
import java.util.Comparator;
import java.util.ArrayList;
import java.util.Enumeration;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.io.NotActiveException;
import java.io.File;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
import java.net.URL;
import java.net.InetAddress;
import org.openide.cookies.ExecCookie;
import org.openide.cookies.SaveCookie;
import org.openide.cookies.DebuggerCookie;
import org.openide.filesystems.*;
import org.openide.loaders.*;
import org.openide.windows.*;
import org.openide.actions.OpenAction;
import org.openide.actions.ViewAction;
import org.openide.text.*;
import org.openide.util.*;
import org.openide.util.actions.*;
import org.openide.nodes.Node;
import org.openide.nodes.Children;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.NodeListener;
import org.openide.execution.ExecInfo;
import org.openide.execution.Executor;
import org.openide.execution.ProcessExecutor;
import org.openide.execution.NbProcessDescriptor;
import org.openide.loaders.ExecSupport;
import org.openide.debugger.DebuggerException;
import org.openide.debugger.DebuggerType;
import org.openide.TopManager;
import org.openide.NotifyDescriptor;
import org.openide.ServiceType;
import org.openide.nodes.Sheet;
import org.openide.nodes.PropertySupport;
import org.netbeans.modules.web.core.jswdk.ServletJspExecutor;
/** Implementation of ExecCookie for internet objects
*
* @author Petr Jiricka
*/
public class WebExecSupport extends Object
implements ExecCookie/*, DebuggerCookie, QueryStringCookie */{
/** constant for class extension */
private static final String CLASS_EXT = "class"; // NOI18N
/** constant for java extension */
private static final String JAVA_EXT = "class"; // NOI18N
/** entry to be associated with */
private MultiDataObject.Entry entry;
public static final String EA_REQPARAMS = "NetBeansAttrReqParams"; // NOI18N
public WebExecSupport(MultiDataObject.Entry entry) throws DataObjectExistsException {
this.entry = entry;
}
/** This method allows subclasses to override the default
* debugger type they want to use for debugging.
*
* @return current implementation returns DebuggerType.getDefault ()
*/
public DebuggerType defaultDebuggerType () {
return DebuggerType.getDefault ();
}
/** This method allows subclasses to override the default
* executor they want to use for debugging.
*
* @return current implementation returns Executor.getDefault ()
*/
public Executor defaultExecutor() {
for (Enumeration en = Executor.executors(); en.hasMoreElements(); ) {
Object exec = en.nextElement();
if (exec instanceof ServletJspExecutor)
return (Executor)exec;
}
return Executor.getDefault ();
}
/** only needs to be here because of a compiler bug */
protected boolean startFailed (IOException ex) {
Executor e = (Executor)choose (ExecSupport.getExecutor (entry), Executor.class, ex);
if (e == null) {
return false;
} else {
try {
ExecSupport.setExecutor (entry, e);
return true;
} catch (IOException exc) {
return false;
}
}
}
/** only needs to be here because of a compiler bug */
protected boolean debugFailed (DebuggerException ex) {
DebuggerType e = (DebuggerType)choose (ExecSupport.getDebuggerType (entry), DebuggerType.class, ex);
if (e == null) {
return false;
} else {
try {
ExecSupport.setDebuggerType (entry, e);
return true;
} catch (IOException exc) {
return false;
}
}
}
/** Opens dialog and asks for different executor or debugger.
* @param current current value
* @param clazz the class to use to locate property editor
* @param ex the exception that caused the problem
* @return the new value or null if choosing failed
*/
private static ServiceType choose (ServiceType current, Class clazz, final Exception ex) {
try {
java.lang.reflect.Method chooser = ExecSupport.class.getDeclaredMethod("choose", new Class[]
{ServiceType.class, Class.class, Exception.class});
chooser.setAccessible(true);
return (ServiceType)chooser.invoke(null, new Object[] {current, clazz, ex});
}
catch (NoSuchMethodException e) {
return current;
}
catch (IllegalAccessException e) {
return current;
}
catch (java.lang.reflect.InvocationTargetException e) {
if (e.getTargetException() instanceof RuntimeException)
throw (RuntimeException)e.getTargetException();
return current;
}
}
/* Starts the class.
*/
public void start () {
new Thread() {
public void run() {
// save the object first
DataObject execDataObj = entry.getDataObject();
SaveCookie sc = (SaveCookie)entry.getDataObject().getCookie(SaveCookie.class);
if (sc != null)
try {
sc.save();
}
catch (IOException e) {}
// now do what we should do
Executor exec = ExecSupport.getExecutor (entry);
if (exec == null) {
exec = defaultExecutor ();
}
try {
exec.execute(new WebExecInfo(entry.getFile().getPackageName ('.'), execDataObj)).result();
} catch (final IOException ex) {
Mutex.EVENT.readAccess (new Runnable () {
public void run () {
if (startFailed (ex)) {
// restart
WebExecSupport.this.start ();
}
}
});
}
}
}.start();
}
/* Start debugging of associated object.
* @param stopOnMain if <code>true</code>, debugger stops on the first line of debugged code
* @exception DebuggerException if the session cannot be started
*/
public void debug (final boolean stopOnMain) throws DebuggerException {
// String[] params = getArguments (); - not needed
DebuggerType t = ExecSupport.getDebuggerType (entry);
if (t == null) {
t = defaultDebuggerType ();
}
DataObject execDataObj = entry.getDataObject();
SaveCookie sc = (SaveCookie)entry.getDataObject().getCookie(SaveCookie.class);
if (sc != null)
try {
sc.save();
}
catch (IOException e) {}
try {
ExecInfo ei = new WebExecInfo (entry.getFile ().getPackageName ('.'), execDataObj);
t.startDebugger (ei, stopOnMain);
// ok, debugger started
return;
} catch (final DebuggerException ex) {
try {
Mutex.EVENT.readAccess (new Mutex.ExceptionAction () {
public Object run () throws DebuggerException {
if (debugFailed (ex)) {
// restart
debug (stopOnMain);
}
return null;
}
});
} catch (org.openide.util.MutexException mx) {
throw (DebuggerException)mx.getException ();
}
}
}
/** Helper method that creates default properties for execution of
* a given support.
* Includes properties to set the executor; debugger; and arguments.
*
* @param set sheet set to add properties to
*/
public void addProperties (Sheet.Set set) {
set.put(createExecutorProperty ());
}
/** Creates the executor property for entry.
* @return the property
*/
private PropertySupport createExecutorProperty () {
return new PropertySupport.ReadWrite (
ExecSupport.PROP_EXECUTION,
Executor.class,
NbBundle.getBundle(ExecSupport.class).getString("PROP_execution"),
NbBundle.getBundle(ExecSupport.class).getString("HINT_execution")
) {
public Object getValue() {
Executor e = ExecSupport.getExecutor (entry);
if (e == null)
return defaultExecutor ();
else
return e;
}
public void setValue (Object val) throws java.lang.reflect.InvocationTargetException {
try {
ExecSupport.setExecutor(entry, (Executor) val);
} catch (IOException ex) {
throw new java.lang.reflect.InvocationTargetException (ex);
}
}
public boolean supportsDefaultValue () {
return true;
}
public void restoreDefaultValue () throws java.lang.reflect.InvocationTargetException {
setValue (null);
}
};
}
public static File getLocalFile(FileObject fo) throws FileStateInvalidException {
FileSystem fs = fo.getFileSystem();
if (fs instanceof LocalFileSystem) {
File root = ((LocalFileSystem)fs).getRootDirectory();
String ap = root.getAbsolutePath();
if (!ap.endsWith(File.separator))
ap += File.separator;
String relPath = fo.getPackageNameExt(File.separatorChar, '.');
return new File(ap + relPath);
}
else
return null;
}
public static boolean waitAndShowInBrowser(URL url, int timeout) {
URL connectURL;
try {
connectURL = new URL(url.getProtocol(), url.getHost(), url.getPort(), "/SOMENONSENSE_NONEXISTING_URL/xxxyyyzzz.nonexistingextension"); // NOI18N
}
catch (MalformedURLException e) {
connectURL = url;
}
if (Util.getUtil().waitForURLConnection(connectURL, timeout, 1000)) {
WebExecSupport.showInBrowser(url);
return true;
}
else {
//PENDING
//TopManager.getDefault().notifyException(new IOException("Could not connect to the server")); // NOI18N
return false;
}
}
public static void showInBrowser(URL url) {
ServletSettings set = ServletSettings.OPTIONS;
if (set.getWebBrowser().equals(ServletSettings.INTERNAL_BROWSER))
TopManager.getDefault().showUrl(url);
else
showInExternal(url);
}
private static void showInExternal(URL url) {
ServletSettings set = ServletSettings.OPTIONS;
NbProcessDescriptor proc = set.getExternalBrowser();
try {
proc.exec(new BrowserFormat(new ExecInfo(""), url.toString())); // NOI18N
} catch (IOException ex) {
TopManager.getDefault().notify(
new NotifyDescriptor.Exception(ex,
NbBundle.getBundle(WebExecSupport.class).getString("EXC_Invalid_Processor")
)
);
}
}
/* Sets execution query string for the associated entry.
* @param qStr the query string
* @exception IOException if arguments cannot be set
*/
public static void setQueryString(FileObject fo, String qStr) throws IOException {
fo.setAttribute (EA_REQPARAMS, qStr);
}
/* Getter for query string associated with given file.
* @return the query string or empty string if no quesy string associated
*/
public static String getQueryString(FileObject fo) {
try {
String qStr = (String)fo.getAttribute (EA_REQPARAMS);
if (qStr != null) {
if ((qStr.length() > 0) && (!qStr.startsWith("?"))) // NOI18N
qStr = "?" + qStr; // NOI18N
return qStr;
}
} catch (Exception ex) {
// null pointer or IOException
}
return ""; // NOI18N
}
/** Translates string name to a DataObject.
* @param file
* @return DataObject or null if not found
* @exception IOException if IO error occurs
*/
public static DataObject classToDataObject(String className) throws IOException {
String file = className.replace('.', '/');
FileObject fo = TopManager.getDefault().getRepository().findResource(file + '.' + CLASS_EXT);
if (fo == null) {
/* class file may not be known to the filesystem yet if it has just been
created by external compilation - in such a case look for the source */
fo = TopManager.getDefault().getRepository().findResource(file + '.' + JAVA_EXT);
}
if (fo == null)
return null;
return TopManager.getDefault().getLoaderPool().findDataObject(fo);
}
/** Returns string for localhost */
public static String getLocalHost() {
try {
return InetAddress.getLocalHost().getHostName();
}
catch (UnknownHostException e) {
return "localhost"; // NOI18N
}
}
/** Default format that can format tags related to execution. Currently this is only the URL.
*/
public static class BrowserFormat extends ProcessExecutor.Format {
/** Tag replaced with the URL */
static final long serialVersionUID =4315554797414856261L;
/** @param info exec info about class to execute
* @param classPath to substitute instead of CLASSPATH
* @param bootClassPath boot class path
* @param repository repository path
* @param library library path
*/
public BrowserFormat (ExecInfo info, String url) {
super(info);
java.util.Map map = getMap ();
map.put (ServletSettings.TAG_URL, url);
}
}
}
/*
* Log
* 25 Gandalf 1.24 1/17/00 Petr Jiricka WebExecSupport - related
* changes.
* 24 Gandalf 1.23 1/16/00 Petr Jiricka Cleanup
* 23 Gandalf 1.22 1/16/00 Petr Jiricka DebuggerCookie removed
* 22 Gandalf 1.21 1/13/00 Petr Jiricka More i18n
* 21 Gandalf 1.20 1/12/00 Petr Jiricka i18n phase 1
* 20 Gandalf 1.19 1/6/00 Petr Jiricka Cleanup
* 19 Gandalf 1.18 1/4/00 Petr Jiricka
* 18 Gandalf 1.17 12/21/99 Petr Jiricka Changes in executing the
* external browser
* 17 Gandalf 1.16 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 16 Gandalf 1.15 10/9/99 Petr Jiricka Changes in
* waitAndShowInBrowser
* 15 Gandalf 1.14 10/8/99 Petr Jiricka Patches for compiler
* errors
* 14 Gandalf 1.13 10/8/99 Petr Jiricka Debugging, fixes
* executor + debugger choice after unsuccesful action
* 13 Gandalf 1.12 10/8/99 Petr Jiricka ClassName -> DataObject
* - improvements
* 12 Gandalf 1.11 10/4/99 Petr Jiricka Reflecting execution API
* changes
* 11 Gandalf 1.10 9/14/99 Petr Jiricka Reflected change in
* semantics of ExecSupport.getExecutor()
* 10 Gandalf 1.9 9/10/99 Petr Jiricka
* 9 Gandalf 1.8 9/10/99 Jaroslav Tulach Changes to services.
* 8 Gandalf 1.7 8/3/99 Petr Jiricka Now uses new class
* ServletSettings
* 7 Gandalf 1.6 7/27/99 Petr Jiricka
* 6 Gandalf 1.5 7/24/99 Petr Jiricka
* 5 Gandalf 1.4 7/20/99 Petr Jiricka
* 4 Gandalf 1.3 7/20/99 Petr Jiricka
* 3 Gandalf 1.2 7/20/99 Petr Jiricka Now uses executors
* 2 Gandalf 1.1 7/16/99 Petr Jiricka
* 1 Gandalf 1.0 7/3/99 Petr Jiricka
* $
*/